package cn.xeblog.plugin.tools.read.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.xeblog.plugin.cache.DataCache;
import cn.xeblog.plugin.tools.read.api.LegadoApi;
import cn.xeblog.plugin.tools.read.entity.Book;
import cn.xeblog.plugin.tools.read.entity.BookType;
import cn.xeblog.plugin.tools.read.entity.Chapter;
import cn.xeblog.plugin.tools.read.entity.LegadoBook;
import cn.xeblog.plugin.util.NotifyUtils;

import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;

/**
 * 章节工具类
 *
 * @author LYF
 * @date 2022-07-20
 */
public class ChapterUtil {

    /**
     * 行，默认8行
     */
    private static final int ROW = 8;
    /**
     * 列，默认26列
     */
    private static final int COLUMNS = 26;

    /**
     * 当前书籍
     */
    private final Book book;
    /**
     * 当前页码
     */
    private int pageIndex;
    /**
     * 章节内容分页列表
     */
    private List<String> contentPage;
    /**
     * legado接口实例
     */
    private LegadoApi legadoApi;

    /**
     * 初始化章节
     *
     * @param book 书籍
     */
    public ChapterUtil(Book book) {
        this(book, 0);
    }

    /**
     * 章节工具类构造器
     *
     * @param book 书籍
     * @param mode 模式，0：初始化；1：最后一页；2：第一页
     */
    public ChapterUtil(Book book, int mode) {
        this.book = book;
        // legado接口实例
        if (book.getType() == BookType.LEGADO) {
            this.legadoApi = new LegadoApi(DataCache.readConfig.getLegadoHost());
        }

        // 章节分页内容列表
        this.contentPage = pagination();
        // 当前页码
        this.pageIndex = getPageIndex(mode);
        // 章节阅读的进度位置
        this.book.setChapterPos(this.pageIndex);
        // 保存进度
        saveBookProgress();
    }

    /**
     * 当前页
     *
     * @return 当前页的内容
     */
    public String currentPage() {
        // 章节阅读的进度位置
        this.book.setChapterPos(this.pageIndex);
        // 指定页的内容
        return contentPage.get(pageIndex);
    }

    /**
     * 下一页
     *
     * @return 下一页的内容
     */
    public String nextPage() {
        // 页码超出了内容页列表大小，跳过
        if (++pageIndex >= contentPage.size()) {
            return "";
        }
        // 保存进度
        saveBookProgress();
        // 更新后的页面内容
        return currentPage();
    }

    /**
     * 上一页
     *
     * @return 上一页内容
     */
    public String lastPage() {
        // 回到上一页，超出范围跳过
        if (--pageIndex < 0) {
            return "";
        }
        // 保存进度
        saveBookProgress();
        // 更新后的页面内容
        return currentPage();
    }

    /**
     * 模式切换，（重新记录位置，计算分页列表、页码）
     */
    public void changeMode() {
        // 章节阅读的进度位置
        int pos = pageIndexToPos();
        // 章节内容分页列表
        this.contentPage = pagination();
        // 页码
        this.pageIndex = posToPageIndex(pos);
    }

    /**
     * 保存进度
     */
    private void saveBookProgress() {
        if (this.book.getType() == BookType.LEGADO) {
            // 构造 Legado 书籍信息
            LegadoBook legadoBook = new LegadoBook();
            legadoBook.setBookUrl(book.getUrl());
            legadoBook.setName(book.getName());
            legadoBook.setAuthor(book.getAuthor());
            legadoBook.setDurChapterIndex(book.getChapterIndex());
            // 2：第一页（章节阅读的进度位置）
            legadoBook.setDurChapterPos(pageIndexToPos());
            legadoBook.setDurChapterTitle(this.book.getCurrentChapter().getTitle());
            legadoBook.setDurChapterTime(DateUtil.current());
            // 调用接口更新进度数据
            ThreadUtil.execute(() -> legadoApi.saveBookProgress(legadoBook));
        }
    }

    /**
     * 分页
     *
     * @return 分页结果
     */
    private List<String> pagination() {
        // 当前章节
        Chapter chapter = this.book.getCurrentChapter();
        String content = "";
        // 通过api获取章节内容
        if (this.book.getType() == BookType.LEGADO) {
            content = this.legadoApi.getBookContent(chapter.getBookUrl(), chapter.getIndex());
        } else {
            // 解析文本获取章节内容
            content = readText(chapter.getStartPointer(), chapter.getEndPointer());
        }

        // 困难模式
        if (book.getHard()) {
            return hardPagination(content);
        } else {
            // 简单模式
            return easyPagination(content);
        }
    }

    /**
     * 简单分页
     *
     * @param content 章节内容
     * @return 分页内容
     */
    private List<String> easyPagination(String content) {
        // 内容分页列表
        List<String> contentPage = new ArrayList<>();

        StringBuilder pageContent = new StringBuilder();
        // 行
        int row = 1;
        // 列
        int col = 0;
        for (int i = 0; i < content.length(); i++) {
            char c = content.charAt(i);
            boolean newlineChar = (c == '\n');
            // 忽略开头第一个就是换行的字符
            if (newlineChar && col == 0) {
                continue;
            }

            // 内容追加并且列下标+1
            pageContent.append(c);
            col++;

            // 是否换行
            boolean newline = (col == COLUMNS || newlineChar);

            // 换行
            if (newline) {
                // 重置列
                col = 0;
                // 当超出最大行
                if (row++ == ROW) {
                    // 内容页+1
                    contentPage.add(pageContent.toString());
                    // 重置页面内容
                    pageContent.setLength(0);
                    row = 0;
                }
            }
        }
        // 读取完后，内容页仍有数据，
        if (pageContent.length() > 0) {
            // 内容页 + 1
            contentPage.add(pageContent.toString());
        }
        return contentPage;
    }

    /**
     * 困难分页
     *
     * @param content 章节内容
     * @return 分页列表
     */
    private List<String> hardPagination(String content) {
        return CollUtil.toList(StrUtil.split(content, DataCache.readConfig.getHardColumns()));
    }

    /**
     * 渲染文本
     *
     * @param startPointer 章节起始位置
     * @param endPointer   章节结束位置
     * @return 渲染后的内容文本
     */
    private String readText(long startPointer, long endPointer) {

        // 随机访问的流，即读写操作的流，
        StringBuilder sb = new StringBuilder();
        try (RandomAccessFile raf = new RandomAccessFile(this.book.getUrl(), "r")) {
            // 行
            String line;
            // 将文件记录移动到章节起始位置
            raf.seek(startPointer);

            while (true) {
                // 读取行
                line = FileUtil.readLine(raf, this.book.getCharset());

                // 行为空或者文件记录中指针的当前位置大于章节结束位置时，退出
                if (line == null || (endPointer != 0 && raf.getFilePointer() > endPointer)) {
                    break;
                }

                // 空行，跳过
                if (line.isEmpty()) {
                    continue;
                }

                // 添加行并换行
                sb.append(line).append("\n");
            }
        } catch (Exception e) {
            // 警告通知
            NotifyUtils.warn("", "小说读取错误：" + e.getMessage());
        }
        return sb.toString();
    }

    /**
     * 获取章节当前页码
     *
     * @param mode 模式，0：初始化；1：最后一页；2：第一页
     * @return 章节当前页码
     */
    private int getPageIndex(int mode) {
        switch (mode) {
            case 0: // 初始化
                // 章节阅读的进度位置
                Integer chapterPos = this.book.getChapterPos();
                // legado书籍计算章节页数
                if (this.book.getType() == BookType.LEGADO) {
                    // 章节阅读的进度位置
                    chapterPos = posToPageIndex(chapterPos);
                }
                // 校验，即章节页数不为空并且并且章节页数在章节内容分页范围内
                boolean valid = chapterPos != null && chapterPos >= 0 && chapterPos < this.contentPage.size();
                // 通过校验,设置章节页数,否则，默认章节页数为零
                return valid ? chapterPos : 0;

            case 1:  // 最后一页
                // 返回章节当前页码
                return this.contentPage.size() - 1;
            case 2: // 第一页
            default:
                // 默认章节当前页码为零
                return 0;
        }
    }

    /**
     * 当前页码转章节阅读的进度位置
     *
     * @return 章节阅读的进度位置
     */
    private int pageIndexToPos() {
        // 章节阅读的进度位置
        int pos = 0;
        // 设置章节阅读的进度位置
        for (int i = 0; i < this.pageIndex; i++) {
            pos += this.contentPage.get(i).length();
        }
        return pos + 1;
    }

    /**
     * 指定章节阅读的进度位置转换为所在的页码
     *
     * @param pos 章节阅读的进度位置
     * @return 章节阅读的进度位置所在的页码
     */
    private int posToPageIndex(int pos) {
        // 章节阅读的进度位置
        int tmpPos = 0;
        // 遍历章节总页数
        for (int i = 0; i < this.contentPage.size(); i++) {
            // 章节每页的长度累加
            tmpPos += this.contentPage.get(i).length();
            // 当章节内容大于当前的位置时，返回当前页码
            if (tmpPos > pos) {
                return i;
            }
        }
        return 0;
    }
}
